function [err] = trace_view(cmd, cmd2, plot_flag)
%
% trace_view: view individual or selected traces, with zooms etc.
% 8/13/01 Paul B. Manis.
%
global DFILE ALLCH ALLFIL
global CONTROL
global AVGDAT
global TR

if(nargin == 0)
    cmd = 'init';
end;
if(~strcmp(cmd,'init') & exist('TR') & isfield(TR, 'inprocess') & TR.inprocess == 1)
    return;
end;


sf = getmainselection;
if(nargin < 3)
    plot_flag = 0;
end;


% make sure structure is initialized and set up
%
if(~exist('TR') | isempty(TR))
    TR.update = 1; % 1 means update the display, 0 means don't bother
    TR.record = 1; % the record number
    TR.sf = sf; % the selection in the main CONTROL database
    TR.store = []; % store flag... 
    TR.inprocess = 0; % set to 1 when already processing a request, and clear when done.
    TR.zoommap = [1000,500,200,100,50,20,10,5,2,1]; % zoom scales
    TR.hps=[];
    TR.avgflag = 0;
    TR.eipsp = 0; % eipsp information is valid = 1; otherwise 0
    TR.hpev=[]; % pointers to figure parent.
    TR.ev= {}; % event time/value pairs, ordered by record
    TR.pk = {}; % peak time/value pairs
    TR.lv = []; % list value (listbox selection)
    TR.m =[];
    TR.ch_up = 1;
    TR.ch_lo = 1;
    TR.time = [];
    
end;

h = findobj('Tag', 'Trace_view'); % check for pre-existing window
if(isempty(h) & ~strcmp(cmd, 'init')) % if none, make one
        tv_init; 
end;


    [DFILE, err] = analysis_setup(DFILE, sf);
    if(err ~= 0)
        return;
    end;

    [protocol, rate, records, pts, frec, lrec, time, TM, ZT, TL, VL] = analysis_setup2(DFILE, sf);
    if(sf ~= TR.sf)
        TR.sf = sf;
        setsliders(DFILE, TR);
    end;
    TR.time = time;
    ALLFIL = ALLCH;
    
    switch (cmd) % use the first argument to dispatch.
    case 'init'
        tv_init;

    case 'close' % call when we close/delete the present window (callback from figure creation)
        ha = findobj('Tag', 'Trace_view');
        if(ishandle(ha))
            delete(ha);
        end;

    case 'printnoui' % print after hiding all the ui's  - then bring them back.
        hui = []; % clear ui list
        uitags = {'R_slider', 'T_positionslider', 'T_zoomslider', 'tv_upper', 'tv_lower', ...
            'tv_record', 'tv_recordlabel', 'tv_info2', 'tv_next_button', 'tv_prev_button', ...
            'tv_erase_button', 'tv_store_button', 'tv_average_button', 'tv_individual_button', ...
            'tv_chuplabel', 'tv_chlowerlabel', 'tv_zoomlabel', 'tv_positionlabel', ...
            'tv_cross1', 'tv_cross2', 'tv_s1', 'tv_s2', 'tv_z1', 'tv_z2'};
        for i = 1:length(uitags);
            hui(i) = findobj('tag', uitags{i});
        end;
        set(hui, 'visible', 'off');
        % do the printing
       try
        print;
        catch
        fprintf(1, 'Printing Failed???\n\n');
        end;
        set(hui, 'visible', 'on');
     
    case 'printdialog'
        printdlg'
            
        
        
    case 'next' % next
        % next trace
        if(TR.record >= length(DFILE.channels))
            return;
        end;
        TR.record = TR.record + 1;
        h1 = findobj('Tag', 'R_slider');
        set(h1, 'Value', TR.record);
        set(h1, 'callback', ''); % disable the slider callback
        TR.update = 1;
        update_plot;
        set(h1, 'callback', 'trace_view(''rslider'')'); % restore the slider callback

    case 'prev' % previous
        if(TR.record <= 1)
            return;
        end;
        TR.record = TR.record - 1;
        h1 = findobj('Tag', 'R_slider');
        set(h1, 'Value', TR.record);
        set(h1, 'callback', ''); % disable the slider callback
        TR.update = 1; % set new flag (redraw base trace).
        update_plot;
        set(h1, 'callback', 'trace_view(''rslider'')'); % restore the slider callback
        
        case {'upperselect', 'lowerselect'}

            hu = findobj('tag', 'tv_upper'); % what channel goes on the upper trace
            ch_up = get(hu, 'value');


            hl = findobj('tag', 'tv_lower'); % what channel goes on the lower trace
            ch_lo = get(hl, 'value');

            if(ch_up > DFILE.channels(1))
                ch_up = 1;
                set(hu, 'value', ch_up); % restore!
            end;
            if(ch_lo > DFILE.channels(1))
                ch_lo = DFILE.channels(1); % set to the highest channel in the list
                set(hl, 'value', ch_lo);
            end;

            TR.update = 1;
            update_plot;

        case 'lowerselect'
            TR.update = 1;
            update_plot;

        case 'store' % store
            store = TR.sf;
            TR.store  = [store thisplot];

    case 'erase' % erase
        TR.store = [];
        update_plot; % clear the storage.

    case 'average'
        TR.avgflag = 1;
        AVGDAT = {};
        for i = 1:length(ALLFIL)
            AVGDAT{i} = mean(ALLFIL{i});
        end;
        TR.update = 1;
        update_plot;
        
    case 'individual'
        TR.avgflag = 0;
        AVGDAT = {};
        TR.update = 1;
        update_plot;
        
    case {'axiszero', 'axisscale'}
        axis_controls(TR, cmd2);

    case {'positionslider', 'zoomslider'} % read the window sliders - start position of window and width of window
        h1 = findobj('Tag', 'T_positionslider');
        h2 = findobj('Tag', 'T_zoomslider');
        update_plot;

    case 'full' % make sliders full view
        h1 = findobj('Tag', 'T_positionslider');
        set(h1, 'value', get(h1, 'min'));
        h2 = findobj('Tag', 'T_zoomslider');
        set(h2, 'value', get(h2, 'min'));
        update_plot;

    case 'rslider' % read the record slider
        hs = findobj('Tag', 'R_slider');
        v1= get(hs, 'Value');
        TR.record = v1;
        TR.m(1) = mean(ALLFIL{TR.ch_up}(TR.record,:));
        TR.m(2) = mean(ALLFIL{TR.ch_lo}(TR.record,:));
        TR.update = 1;
        update_plot;

        case 'eipspload'
        if(isfield(CONTROL(TR.sf), 'EIPSP') & ~isempty(CONTROL(TR.sf).EIPSP))
            E = CONTROL(TR.sf).EIPSP; % get the main structure to make life easy
            k = 0;
            for isrc = E.srcchan
                k = k + 1;
                    ev = eval([sprintf('E.ev%d{%d};', isrc, TR.record)]);
                    tev = eval([sprintf('E.tev%d{%d};', isrc, TR.record)]);
                    pk = eval([sprintf('E.pk%d{%d};', isrc, TR.record)]);
                    tpk = eval([sprintf('E.tpk%d{%d};', isrc, TR.record)]);
                    TR.ev{k} = [tev ev];
                    TR.pk{k} = [tpk pk];
            end;
            hev1 = findobj('tag', 'tv_eipsplist1');
            set(hev1, 'string', num2str(TR.ev{1}(:,1)));
            set(hev1, 'value', 1);
            hev2 = findobj('tag', 'tv_eipsplist2');
            set(hev2, 'string', num2str(TR.ev{2}(:,1)));
            set(hev2, 'value', 1);
            TR.eipsp = 1;
            TR.lv=[1 1];
            TR.update = 1;
            jsrc = 0;
            for isrc = E.srcchan
                jsrc = jsrc + 1;
                ALLFIL{isrc}  = ALLCH{isrc};
                trace = ALLFIL{isrc};
                for i=1:length(DFILE.record)
                    fsamp = 1000000/(DFILE.rate(i)*DFILE.nr_channel(i)); % get sampling frequency
                    fco1 = 1000;		% highpass cutoff frequency in Hz
                    fco2 = E.lpf(jsrc); % low-pass cutoff frequency in Hz
                    wco1 = fco1/(fsamp/2); % wco of 1 is for half of the sample rate, so set it like this...
                    wco2 = fco2/(fsamp/2);
                    if(isfield(E, 'notch'))
                        fn1 = E.notch(jsrc)+0.02*E.notch(jsrc);
                        fn2 = E.notch(jsrc)-0.02*E.notch(jsrc);
                    else
                        notch = 800*ones(length(E.srcchan), 1);
                        fn1 = notch(jsrc)+0.02*notch(jsrc);
                        fn2 = notch(jsrc)-0.02*notch(jsrc);
                    end;
                    nco1 = fn1/(fsamp/2);
                    nco2 = fn2/(fsamp/2);
                    if(wco1 < 1 & wco2 < 1 & nco1 < 1 & nco2 < 1) % if wco is > 1 then this is not a filter!
                        [bn, an] = fir1(24, [nco2 nco1], 'stop');
                        tracel = filtfilt(bn, an, trace(i,:));
                        [b, a] = fir1(24, wco2); % fir type filter... seems to work best, with highest order min distortion of dv/dt...
                        tracel = filtfilt(b, a, tracel); % filter all the traces...
                        trace(i,:) = tracel;
                        ALLFIL{isrc}(i,:) = tracel; % save smoothed trace...
                    else
                        fprintf(1, 'ng: wco1 = %f wco2 = %f\n', wco1, wco2);
                    end
                end;
            end;

            update_plot;
        else
            TR.eipsp = 0;
        end;
        
    case 'eipsp_lb1'
        hev1 = findobj('tag', 'tv_eipsplist1');
        v1 = get(hev1, 'value');
        TR.lv(1) = v1;
        TR.update = 1;
        update_plot;

    case 'eipsp_lb2'
        hev2 = findobj('tag', 'tv_eipsplist2');
        v2 = get(hev2, 'value');
        TR.lv(2) = v2;
        TR.update = 1;
        update_plot;

    case 'expand' % expand data plot around the current point.
%         h1 = findobj('Tag', 'T_slider');
%         set(h1, 'callback', ''); % disable the slider callback
%         h2 = findobj('Tag', 'T_slider2');
%         set(h2, 'callback', ''); % disable the slider callback
%         axinfo = get(gca, 'UserData'); % get the axis information...
%         pos = axinfo.curpos;  % origin...
%         lims = get(gca, 'Xlim');
%         slidepos = (100*pos(1)/(lims(2)-lims(1)));
%         v1= get(h1, 'Value');
%         %set(h1, 'Value',  slidepos);
%         v2 = get(h1, 'Value');
%         TR.slide = [v1 v2];
%         update_plot;
%         set(h1, 'callback', 'trace_view(''tslider'')'); % restore the slider callback
%         set(h2, 'callback', 'trace_view(''tslider2'')'); % restore the slider callback
%

    otherwise
        QueMessage(sprintf('Trace View: unrecognized command: %s', char(cmd)));
end;


function tv_init()
% routine to set up the display etc. on the first go around. (avoid recursion).
global DFILE TR ALLFIL
h = findobj('Tag', 'Trace_view'); % check for pre-existing window
if(isempty(h)) % if none, make one
    if(isempty(h))
        open('tv.fig');
    end;
    h = findobj('tag', 'Trace_view');
    % Use system color scheme for figure:
end
figure(h); % otherwise, select it
datac('addwindow', 'Trace_view');
if(~isempty(DFILE))
    set(h, 'name', [DFILE.filename DFILE.ext]);
end;
hi = findobj('tag', 'tv_info1');
if(~isempty(hi))
    set(hi, 'string', sprintf('File: %s  [%d-%d]  %s', [DFILE.filename DFILE.ext], DFILE.frec, ...
        DFILE.lrec, date));
end;
hu = findobj('tag', 'tv_upper'); % what channel goes on the upper trace
set(hu, 'value', 1);


hl = findobj('tag', 'tv_lower'); % what channel goes on the lower trace
set(hl, 'value', 3);

TR.hps(1) = findobj('Tag', 'tv_axes1');
axes(TR.hps(1));
cla;
TR.hpl(1) = line([0 1], [NaN NaN], 'Parent', TR.hps(1));
hold on;
TR.hpev(1) = plot([0 1], [NaN NaN], 'ro', 'Parent', TR.hps(1), ...
    'markersize', 4.5, 'markeredgecolor', 'r', 'markerfacecolor', 'w', 'linewidth', 2  );
TR.hps(2) = findobj('Tag', 'tv_axes2');
axes(TR.hps(2));
cla;
TR.hpl(2) = line([0 1], [NaN NaN], 'Parent', TR.hps(2));
hold on;
TR.hpev(2) = plot([0 1], [NaN NaN],  'ro', 'Parent', TR.hps(2), ...
        'markersize', 4.5, 'markeredgecolor', 'r', 'markerfacecolor', 'w', 'linewidth', 2  );


set(h,'Color',get(0,'defaultUicontrolBackgroundColor'));
TR.update = 1;
TR.record = 1;
TR.inprocess = 0;
TR.avgflag = 0;
setsliders(DFILE, TR);
axis_controls(TR, 1);
axis_controls(TR, 2);

    hu = findobj('tag', 'tv_upper'); % what channel goes on the upper trace
    TR.ch_up = get(hu, 'value');


    hl = findobj('tag', 'tv_lower'); % what channel goes on the lower trace
    TR.ch_lo = get(hl, 'value');

    if(TR.ch_up > DFILE.channels(1))
        TR.ch_up = 1;
        set(hu, 'value', TR.ch_up); % restore!
    end;
    if(TR.ch_lo > DFILE.channels(1))
        TR.ch_lo = DFILE.channels(1); % set to the highest channel in the list
        set(hl, 'value', TR.ch_lo);
    end;
        TR.m(1) = mean(ALLFIL{TR.ch_up}(TR.record,:));
        TR.m(2) = mean(ALLFIL{TR.ch_lo}(TR.record,:));



update_plot;
disp 'tv_init'

        

function update_plot()

global DFILE ALLFIL TR AVGDAT

if(TR.inprocess == 1) % don't process request if currently busy drawing.
    return;
end;
h = findobj('Tag', 'Trace_view'); % check for pre-existing window
if(isempty(h)) % if none, make one
    return;
end
TR.inprocess = 1;

figure(h); % otherwise, select it
hr = findobj('tag', 'tv_record');
if(~isempty(hr))
    set(hr, 'String', sprintf('%d', DFILE.record(TR.record)));
end;

hu = findobj('tag', 'tv_upper'); % what channel goes on the upper trace
ch_up = get(hu, 'value');


hl = findobj('tag', 'tv_lower'); % what channel goes on the lower trace
ch_lo = get(hl, 'value');

if(ch_up > DFILE.channels(1))
    ch_up = 1;
    set(hu, 'value', ch_up); % restore!
end;
if(ch_lo > DFILE.channels(1))
    ch_lo = DFILE.channels(1); % set to the highest channel in the list
    set(hl, 'value', ch_lo);
end;

    
fsize = 7;
msize = 3;
hcp1 = findobj('tag', 'tv_cursorpos1');
hcp2 = findobj('tag', 'tv_cursorpos2');
msg_pos1 = get(hcp1, 'Position');
msg_pos2 = get(hcp2, 'Position');
%msg_pos3 = [0.85 0.15 0.15 0.07];

k = TR.record;
ctl_sf=TR.sf;
store = TR.store;


npts=DFILE.nr_points;
if(length(DFILE.nr_channel) > 1)
    j = k;
else
    j = 1;
end;
tmax = max(max(TR.time'));

[s1p, s2p] = getsliders;
%fprintf(1, 'Sliders: 1: %7.2f    2: %7.2f\n', s1p, s2p);

% calculate slider positions/points.
pltstart = floor(npts*(s1p/100)); % as a percentage
if(TR.eipsp)
    pltzero = floor((TR.ev{1}(TR.lv(1), 1))/(0.001*DFILE.rate(TR.record)*DFILE.nr_channel(TR.record)));
    pltstart = pltzero;
else
    pltstart = floor(npts*(s1p/100)); % as a percentage
end;
if(pltstart < 1)
    pltstart = 1;
end;


pltdur = floor(npts/s2p);
if(pltdur < 100)
    pltdur = 100; % minimum of 100 points
end;
pltend = pltstart + pltdur;
if(pltend > npts)
    pltend = npts;
    pltstart = pltend-pltdur;
end;
if(TR.eipsp)
    dp = pltend - pltstart;
    pltstart = pltzero - floor(dp/2);
    if(pltstart < 1) 
        pltstart = 1;
    end;
    pltend = pltzero + ceil(dp/2);
    if(pltend > length(TR.time(k,:)))
        pltend = length(TR.time(k,:));
    end;
end;
if(pltstart < 1) pltstart = 1; end;

if(TR.update)
    if(~isempty(TR.hps(1)))
        axes(TR.hps(1));
        if(TR.avgflag == 0)
            set(TR.hpl(1), 'XData', TR.time(k,pltstart:pltend), 'YData', ALLFIL{ch_up}(k,pltstart:pltend), 'color', 'k', 'erasemode', 'none'); % data in black, and thin
            if(TR.eipsp == 1)
                set(TR.hpev(1), 'XData', [TR.ev{k}(TR.lv(1), 1) TR.pk{k}(TR.lv(1), 1)], ...
                    'YData', [TR.ev{k}(TR.lv(1), 2) TR.pk{k}(TR.lv(1), 2)]+TR.m(1));
            end;
        else
            set(TR.hpl(1), 'XData', TR.time(k,pltstart:pltend), 'YData', AVGDAT{ch_up}(pltstart:pltend), 'color', 'k', 'erasemode', 'none'); % data in black, and thin
        end;

        datac_setcrosshair(TR.hps(1), 'tv_cross1', 'ms', 'mV', msg_pos1, 'trace_view(''expand'');');
    end;
    if(~isempty(TR.hps(2)))
        axes(TR.hps(2));
        if(TR.avgflag == 0)
            set(TR.hpl(2), 'XData', TR.time(k,pltstart:pltend), 'YData', ALLFIL{ch_lo}(k,pltstart:pltend), 'color', 'b', 'erasemode', 'none');
        else
             set(TR.hpl(2), 'XData', TR.time(k,pltstart:pltend), 'YData', AVGDAT{ch_lo}(pltstart:pltend), 'color', 'b', 'erasemode', 'none');
       end;

        datac_setcrosshair(TR.hps(2), 'tv_cross2', 'ms', 'mV', msg_pos2, 'trace_view(''expand'');');
    end;
    TR.update = 0;
end;

set(TR.hps, 'FontSize', 10);

if(~isempty(TR.hps(1)) & ~isempty(TR.hps(2)))
    set(TR.hps, 'Xlim', [TR.time(k,pltstart) TR.time(k,pltend)]);
end;

TR.inprocess = 0;


function setsliders(DFILE, TR)
%
% set the sliders up according to the data we have read
disp 'setsliders'
hsl = findobj('tag', 'R_slider'); % set the record list box to show the record list.
if(~isempty(hsl))
    rl = length(DFILE.record);
    set(hsl, 'min', 1);
    set(hsl, 'max', rl);
    set(hsl, 'Value', TR.record);
    x=fliplr(DFILE.record');
    s=[];
    for i = 1:length(x)
        s=[s sprintf('%d', x(i))];
        if(i < length(x))
            s = [s '|'];
        end;
    end;
    set(hsl, 'String', s);
    set(hsl, 'callback', 'trace_view(''rslider'')'); % restore the callback
end;
hzsl = findobj('tag', 'T_zoomslider'); % get the zoom listbox also
set(hzsl, 'min', 1);
set(hzsl, 'max', length(TR.zoommap)); % set the zoom so it has as many steps as in the map
set(hzsl, 'value', length(TR.zoommap));
s=[];
for i = 1:length(TR.zoommap)
    s = [s sprintf('%d', TR.zoommap(i))];
    if(i < length(x))
        s = [s '|'];
    end;
end;
set(hzsl, 'String', s); % serial levels, no matter how slider moves
set(hzsl, 'callback', 'trace_view(''zoomslider'')'); % restore the slider callback

  
hps1 = findobj('tag', 'T_positionslider'); % get the slider that goes along the trace
set(hps1, 'min', 0);
set(hps1, 'value', 0); % start at LHS
set(hps1, 'max', 100); % percentage position along trace
set(hps1, 'SliderStep', [0.005 0.1]); % allow small steps and bigger steps
set(hps1, 'callback', 'trace_view(''positionslider'')'); % restore the slider callback


function [s1, s2] = getsliders()

global TR

s1 = 0;
s2 = 1;
h1 = findobj('tag', 'T_positionslider');
if(~isempty(h1))
    s1 = fix(get(h1, 'value'));
    % scale the value...
end;

h2 = findobj('tag', 'T_zoomslider');
if(~isempty(h2))
    s2 = get(h2, 'value');
    s2 = TR.zoommap(s2); % translate it
end;

function axis_controls(TR, cmd2)
%
tz = sprintf('tv_z%d', cmd2);
ts = sprintf('tv_s%d', cmd2);
hs = findobj('tag', ts);
hz = findobj('tag', tz);
v = get(hs, 'value');
st = get(hs, 'string');
sv = st{v};
if(strmatch(sv, 'auto'))
    set(TR.hps(cmd2), 'YLimMode', 'auto');
else
    set(TR.hps(cmd2), 'YLimMode', 'manual');
    fs = str2num(char(sv))*10;
    sz = get(hz, 'string');
    vz = get(hz, 'value');
    sz=sz(vz);
    if(strcmp(sz, 'mean')) % use the mean value of the data in the window... equal +/-
        zp = 0.5;
    end;
    zp = str2num(char(sz))/100; % convert to a fraction from the bottom.
    zp = 1-zp;
    yl = [(zp-1)*fs, zp*fs];
    set(TR.hps(cmd2), 'YLim', yl);
end;

